package com.se.dao.mysql;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.http.HttpRequest;
import com.se.domain.dto.ImageFileDTO;
import com.se.domain.mysql.ImgDO;
import com.se.domain.qo.ImgQO;
import com.se.domain.vo.ImgVO;
import com.se.enums.ResultCode;
import com.se.exception.ResultException;
import com.se.mapper.ImgMapper;
import com.se.util.MyDateUtil;
import com.se.util.MySupplier;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Repository;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.text.SimpleDateFormat;
import java.util.*;

@Repository
@Slf4j
public class ImgDao {
	@Autowired
	private ImgMapper imgMapper;
	@Value("${image.urlPrefix}")
	private String imgUrlPrefix;
	
	public String getImgUrlByPath(String path){
		return this.imgUrlPrefix + path;
	}
	
	//通过imgQO 获取 imgUrl
	public String getImgUrlByQO(ImgQO imgQO){
		switch (imgQO.getType()){
			case ImgDO.Type.OUTER -> {
				return imgQO.getUrl();
			}
			case ImgDO.Type.LOCAL -> {
				return this.getImgUrlByPath(imgQO.getPath());
			}
			default -> {
				return null;
			}
		}
	}
	
	//通过ImgId查询imgUrl
	public String getImgUrlById(Long imgId){
		if(imgId == null){
			return null;
		}
		ImgQO qo = imgMapper.getActiveQOById(imgId);
		if(qo == null){
			return null;
		}
		return this.getImgUrlByQO(qo);
	}
	
	public Map<Long, String> mapImgUrl(List<Long> imgIdList) {
		if(imgIdList.isEmpty()){
			return new TreeMap<>();
		}
		List<ImgQO> qoList = imgMapper.listActiveQOByIdList(imgIdList);
		
		HashMap<Long, String> map = new HashMap<>();
		for (ImgQO qo : qoList) {
			map.put(qo.getImgId(), this.getImgUrlByQO(qo));
		}
		return map;
	}

	public Map<Long, ImgVO> mapVOByImgIdList(List<Long> imgIds) {
		if(imgIds.isEmpty()){
			return Collections.emptyMap();
		}
		List<ImgQO> qoList = imgMapper.listActiveQOByIdList(imgIds);
		HashMap<Long, ImgVO> map = new HashMap<>();
		for (ImgQO qo : qoList) {
			map.put(qo.getImgId(),new ImgVO(qo.getImgId(), this.getImgUrlByQO(qo)) );
		}
		return map;
	}
	public void insert(ImgDO imgDO) {
		imgMapper.insertImg(imgDO);
	}
	public void insertAll(List<ImgDO> imgDOList) {
		if(imgDOList.isEmpty()){
			return;
		}
		imgMapper.insertAll(imgDOList);
	}
	
	public ImgQO getQOById(Long imgId) {
		return imgMapper.getQOById(imgId);
	}
	
	public void logicDelById(Long imgId) {
		if(imgId != null)
			imgMapper.logicDeleteById(imgId);
	}

	@Async("fileAsyncExecutor")
	public void logicDelByIdList(List<Long> imgIdList) {
		if(imgIdList.isEmpty()){
			return;
		}
		imgMapper.logicDeleteByIdList(imgIdList);
	}

	@Async("fileAsyncExecutor")
	public void delByIdList(List<Long> imgIdList) {
		if(imgIdList.isEmpty()){
			return;
		}
		List<ImgQO> imgQOList = imgMapper.listActiveQOByIdList(imgIdList);
		for (ImgQO imgQO : imgQOList) {
			FileUtil.del(imgQO.getPath());
		}
		imgMapper.deleteByIdList(imgIdList);
	}
	
	@Value("${image.path}")
	String imgDir;
	
	//
	
	/**
	 * 切入图片保存与删除方法，减少冗余代码
	 * @param supplier 函数式接口，包含业务逻辑相关代码
	 * @param imgArray 图片DTO数组
	 * @throws ResultException 异常
	 */
	public void saveImgFileAspect(
			MySupplier supplier,
			ImageFileDTO...imgArray
	) throws ResultException {
		try {
			//保存图片
			this.saveImgFile(imgArray);
			//调用函数
			supplier.run();
		}catch (IOException e){
			log.error("图片保存错误", e);
			//删除已保存图片
			this.deleteImgFile(imgArray);
			throw new ResultException(ResultCode.FAIL);
		}
	}

	public static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
	//生成图片父目录
	private String generateImgFileDir(){
		String[] split = sdf.format(new Date()).split("-");
		String year = split[0],month = split[1],day = split[2];
		StringJoiner dir = new StringJoiner("/");
		dir.add(this.imgDir).add(year).add(month).add(day);
		return dir.toString();
	}
	
	//保存图片
	private void saveImgFile(ImageFileDTO... imageFileDTOList) throws IOException {
		for (ImageFileDTO dto : imageFileDTOList) {
			File saveFile;
			saveFile = new File(dto.getPath());
			FileUtil.touch(saveFile);
			dto.setSaved(true);
			if(dto.getType() == ImgDO.Type.LOCAL){
				//本地存储
				dto.getFile().transferTo(saveFile);
			}else if(dto.getType() == ImgDO.Type.OUTER){
				//网络存储
				FileOutputStream outputStream = null;
				InputStream inputStream = null;
				try {
					FileUtil.touch(saveFile);
					outputStream = new FileOutputStream(saveFile);
					inputStream = HttpRequest.get(dto.getSrc()).execute().bodyStream();
					byte[] buffer = new byte[1024];
					int len = 0;
					while ((len = inputStream.read(buffer)) != -1) {
						outputStream.write(buffer, 0, len);
					}
				} finally {
					if (inputStream != null) {
						inputStream.close();
					}
					if (outputStream != null) {
						outputStream.close();
					}
				}
			}
			dto.setSaved(true);
			log.info("保存图片：{}",dto.getPath());
		}
	}
	
	//删除图片文件
	private void deleteImgFile(ImageFileDTO... imgArray) {
		for (ImageFileDTO dto : imgArray) {
			if(dto.isSaved()){
				FileUtil.del(dto.getPath());
				dto.setSaved(false);
				log.info("异常删除图片：{}",dto.getPath());
			}
		}
	}
	
	//生成外部图片项
	public ImageFileDTO generateOuterImageFileDTO(String src){
		String dir = this.generateImgFileDir();
		String fileName = "web-"+IdUtil.simpleUUID();
		String path = dir + "/" +fileName;
		return ImageFileDTO.buildFromUrl(path, src);
	}
	
	//生成并检查图片文件项
	public ImageFileDTO[] generateImageFileDTO(int maxLength, int maxSize, MultipartFile... imgFileList) throws ResultException {
		List<ImageFileDTO> imageFileDTOList = new LinkedList<>();
		if(imgFileList != null && imgFileList.length > 0){
			
			//参数校验
			if(imgFileList.length > maxLength){
				throw new ResultException(ResultCode.INVALID_FILE);
			}
			String dir = this.generateImgFileDir();
			for (MultipartFile file : imgFileList) {
				//文件大小判断
				if(file.getSize() > maxSize){
					throw new ResultException(ResultCode.INVALID_FILE);
				}
				//文件名判断
				String originalFilename = file.getOriginalFilename();
				if (originalFilename == null || originalFilename.isEmpty()) {
					throw new ResultException(ResultCode.INVALID_FILE);
				}
				int suffixOffset = originalFilename.lastIndexOf(".");
				if(suffixOffset == -1 || suffixOffset == originalFilename.length() - 1){
					throw new ResultException(ResultCode.INVALID_FILE);
				}
				String suffix = originalFilename.substring(suffixOffset);
				switch (suffix){
					case ".jpg":
					case ".jpeg":
					case ".png":
						break;
					default:
						throw new ResultException(ResultCode.INVALID_FILE);
				}
				
				//生成ImageFileDTO项
				String fileName = IdUtil.simpleUUID()+suffix;
				String filePath = dir + "/" +fileName;
				imageFileDTOList.add(ImageFileDTO.buildFromFile(filePath, file));
			}
		}
		
		
		return imageFileDTOList.toArray(new ImageFileDTO[0]);
	}



}
